package com.gzc.just.play.last.war.balanceserver.manager;



import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.stereotype.Component;



import jakarta.annotation.PostConstruct;

import java.util.*;

import java.util.concurrent.ConcurrentHashMap;

import java.util.concurrent.atomic.AtomicLong;



/**

 * 鏈嶅姟鍣ㄧ＄悊鍣

 * 绠＄悊鎵鏈夋敞鍐岀殑鏈嶅姟鍣锛屾彁渚涜礋杞藉潎琛″拰鍋ュ悍妫鏌ュ姛鑳

 */

@Component("balance-serverManager")
public class ServerManager {

    private static final Logger logger = LoggerFactory.getLogger(ServerManager.class);



    // 鏈嶅姟鍣↖D鍒版湇鍔″櫒淇℃伅鐨勬槧灏

    private final ConcurrentHashMap<Long, ServerInfo> servers = new ConcurrentHashMap<>();



    // 骞宠　鏈嶅姟鍣ㄥ惎鍔ㄦ椂闂

    private final long startTime = System.currentTimeMillis();



    // 鏈嶅姟鍣↖D鐢熸垚鍣

    private final AtomicLong serverIdGenerator = new AtomicLong(10000);



    @PostConstruct

    public void init() {

        // 鍒濆嬪寲涓浜涢粯璁ょ殑鏈嶅姟鍣锛堢ず渚嬶級

        addDefaultServers();



        logger.info("ServerManager initialized with {} servers", servers.size());

    }



    /**

     * 娣诲姞榛樿ゆ湇鍔″櫒锛堢ず渚嬶級

     */

    private void addDefaultServers() {

        // 娣诲姞涓浜涚ず渚嬪満鏅鏈嶅姟鍣

        addServer(new ServerInfo(

                serverIdGenerator.incrementAndGet(),

                "SceneServer-1",

                "scene",

                "127.0.0.1",

                8081,

                0,

                100,

                "running",

                System.currentTimeMillis()

        ));



        addServer(new ServerInfo(

                serverIdGenerator.incrementAndGet(),

                "SceneServer-2",

                "scene",

                "127.0.0.1",

                8082,

                20,

                100,

                "running",

                System.currentTimeMillis()

        ));



        // 娣诲姞涓浜涚ず渚嬬櫥褰曟湇鍔″櫒

        addServer(new ServerInfo(

                serverIdGenerator.incrementAndGet(),

                "LoginServer-1",

                "login",

                "127.0.0.1",

                8083,

                5,

                50,

                "running",

                System.currentTimeMillis()

        ));



        // 娣诲姞涓浜涚ず渚嬩腑蹇冩湇鍔″櫒

        addServer(new ServerInfo(

                serverIdGenerator.incrementAndGet(),

                "CentralServer-1",

                "central",

                "127.0.0.1",

                8084,

                30,

                100,

                "running",

                System.currentTimeMillis()

        ));

    }



    /**

     * 鏈嶅姟鍣ㄤ俊鎭绫

     */

    public static class ServerInfo {

        private final long serverId;

        private final String serverName;

        private final String serverType;

        private final String host;

        private final int port;

        private volatile int currentLoad;

        private final int maxLoad;

        private volatile String status;

        private final long registerTime;

        private volatile long lastHeartbeatTime;



        public ServerInfo(long serverId, String serverName, String serverType, String host, int port,

                          int currentLoad, int maxLoad, String status, long registerTime) {

            this.serverId = serverId;

            this.serverName = serverName;

            this.serverType = serverType;

            this.host = host;

            this.port = port;

            this.currentLoad = currentLoad;

            this.maxLoad = maxLoad;

            this.status = status;

            this.registerTime = registerTime;

            this.lastHeartbeatTime = registerTime;

        }



        // Getters

        public long getServerId() {

            return serverId;

        }



        public String getServerName() {

            return serverName;

        }



        public String getServerType() {

            return serverType;

        }



        public String getHost() {

            return host;

        }



        public int getPort() {

            return port;

        }



        public int getCurrentLoad() {

            return currentLoad;

        }



        public int getMaxLoad() {

            return maxLoad;

        }



        public String getStatus() {

            return status;

        }



        public long getRegisterTime() {

            return registerTime;

        }



        public long getLastHeartbeatTime() {

            return lastHeartbeatTime;

        }



        // Setters

        public void setCurrentLoad(int currentLoad) {

            this.currentLoad = currentLoad;

        }



        public void setStatus(String status) {

            this.status = status;

        }



        public void setLastHeartbeatTime(long lastHeartbeatTime) {

            this.lastHeartbeatTime = lastHeartbeatTime;

        }



        /**

         * 鑾峰彇璐熻浇鐧惧垎姣

         */

        public double getLoadPercentage() {

            return maxLoad > 0 ? (double) currentLoad / maxLoad * 100 : 0;

        }

    }



    /**

     * 娣诲姞鏈嶅姟鍣

     */

    public boolean addServer(ServerInfo serverInfo) {

        if (servers.containsKey(serverInfo.getServerId())) {

            logger.warn("Server {} already exists, updating", serverInfo.getServerId());

        }



        servers.put(serverInfo.getServerId(), serverInfo);

        logger.info("Added server: {} ({})", serverInfo.getServerName(), serverInfo.getServerId());

        return true;

    }



    /**

     * 绉婚櫎鏈嶅姟鍣

     */

    public boolean removeServer(long serverId) {

        ServerInfo serverInfo = servers.remove(serverId);

        if (serverInfo != null) {

            logger.info("Removed server: {} ({})", serverInfo.getServerName(), serverId);

            return true;

        }

        return false;

    }



    /**

     * 鏇存柊鏈嶅姟鍣ㄧ姸鎬

     */

    public boolean updateServerStatus(long serverId, Map<String, Object> statusUpdate) {

        ServerInfo serverInfo = servers.get(serverId);

        if (serverInfo == null) {

            logger.warn("Server {} not found for status update", serverId);

            return false;

        }



        // 鏇存柊璐熻浇

        if (statusUpdate.containsKey("load")) {

            try {

                int load = Integer.parseInt(statusUpdate.get("load").toString());

                serverInfo.setCurrentLoad(load);

            } catch (Exception e) {

                logger.error("Invalid load value for server {}: {}", serverId, statusUpdate.get("load"));

            }

        }



        // 鏇存柊鐘舵

        if (statusUpdate.containsKey("status")) {

            serverInfo.setStatus(statusUpdate.get("status").toString());

        }



        // 鏇存柊蹇冭烦鏃堕棿

        serverInfo.setLastHeartbeatTime(System.currentTimeMillis());



        logger.debug("Updated status for server: {}", serverId);

        return true;

    }



    /**

     * 鑾峰彇鏈嶅姟鍣ㄤ俊鎭

     */

    public ServerInfo getServerInfo(long serverId) {

        return servers.get(serverId);

    }



    /**

     * 鑾峰彇鏈嶅姟鍣ㄧ姸鎬侊紙Map鏍煎紡锛

     */

    public Map<String, Object> getServerStatus(long serverId) {

        ServerInfo serverInfo = servers.get(serverId);

        if (serverInfo == null) {

            return null;

        }



        Map<String, Object> map = new HashMap<>();

        map.put("serverId", serverInfo.getServerId());

        map.put("serverName", serverInfo.getServerName());

        map.put("serverType", serverInfo.getServerType());

        map.put("host", serverInfo.getHost());

        map.put("port", serverInfo.getPort());

        map.put("load", serverInfo.getCurrentLoad());

        map.put("maxLoad", serverInfo.getMaxLoad());

        map.put("loadPercentage", serverInfo.getLoadPercentage());

        map.put("status", serverInfo.getStatus());

        map.put("registerTime", serverInfo.getRegisterTime());

        map.put("lastHeartbeatTime", serverInfo.getLastHeartbeatTime());

        return map;

    }



    /**

     * 鑾峰彇鏈嶅姟鍣ㄥ仴搴风姸鎬

     */

    public Map<String, Object> getServerHealthStatus(long serverId) {

        ServerInfo serverInfo = servers.get(serverId);

        if (serverInfo == null) {

            return null;

        }



        long timeSinceLastHeartbeat = System.currentTimeMillis() - serverInfo.getLastHeartbeatTime();

        boolean isHealthy = "running".equals(serverInfo.getStatus()) &&

                timeSinceLastHeartbeat < 30000; // 30绉掑唴鏈夊績璺宠や负鍋ュ悍



        return Map.of(

                "serverId", serverInfo.getServerId(),

                "serverType", serverInfo.getServerType(),

                "status", serverInfo.getStatus(),

                "healthy", isHealthy,

                "loadPercentage", serverInfo.getLoadPercentage(),

                "timeSinceLastHeartbeat", timeSinceLastHeartbeat

        );

    }



    /**

     * 鑾峰彇鎵鏈夋湇鍔″櫒鐘舵

     */

    public List<Map<String, Object>> getAllServerStatus() {

        List<Map<String, Object>> serverStatusList = new ArrayList<>();



        for (ServerInfo serverInfo : servers.values()) {

            serverStatusList.add(getServerStatus(serverInfo.getServerId()));

        }



        return serverStatusList;

    }



    /**

     * 鑾峰彇鎵鏈夋湇鍔″櫒淇℃伅

     */

    public List<ServerInfo> getAllServers() {

        return new ArrayList<>(servers.values());

    }



    /**

     * 鏍规嵁绫诲瀷鑾峰彇鏈嶅姟鍣ㄥ垪琛

     */

    public List<Map<String, Object>> getServersByType(String serverType) {

        List<Map<String, Object>> serverList = new ArrayList<>();



        for (ServerInfo serverInfo : servers.values()) {

            if (serverType.equals(serverInfo.getServerType())) {

                serverList.add(getServerStatus(serverInfo.getServerId()));

            }

        }



        return serverList;

    }



    /**

     * 鑾峰彇璐熻浇鏈灏忕殑鏈嶅姟鍣

     */

    public Map<String, Object> getLeastLoadedServer() {

        ServerInfo leastLoadedServer = null;

        int minLoad = Integer.MAX_VALUE;



        for (ServerInfo serverInfo : servers.values()) {

            if ("running".equals(serverInfo.getStatus()) &&

                    serverInfo.getCurrentLoad() < minLoad &&

                    serverInfo.getCurrentLoad() < serverInfo.getMaxLoad()) {



                minLoad = serverInfo.getCurrentLoad();

                leastLoadedServer = serverInfo;

            }

        }



        return leastLoadedServer != null ? getServerStatus(leastLoadedServer.getServerId()) : null;

    }



    /**

     * 鏍规嵁绫诲瀷鑾峰彇璐熻浇鏈灏忕殑鏈嶅姟鍣

     */

    public Map<String, Object> getLeastLoadedServerByType(String serverType) {

        ServerInfo leastLoadedServer = null;

        int minLoad = Integer.MAX_VALUE;



        for (ServerInfo serverInfo : servers.values()) {

            if (serverType.equals(serverInfo.getServerType()) &&

                    "running".equals(serverInfo.getStatus()) &&

                    serverInfo.getCurrentLoad() < minLoad &&

                    serverInfo.getCurrentLoad() < serverInfo.getMaxLoad()) {



                minLoad = serverInfo.getCurrentLoad();

                leastLoadedServer = serverInfo;

            }

        }



        return leastLoadedServer != null ? getServerStatus(leastLoadedServer.getServerId()) : null;

    }



    /**

     * 鑾峰彇娲昏穬杩炴帴鏁帮紙绀轰緥锛

     */

    public int getActiveConnectionCount() {

        // 瀹為檯瀹炵幇涓搴旇ョ粺璁″疄闄呯殑娲昏穬杩炴帴鏁

        // 杩欓噷杩斿洖涓涓绀轰緥鍊

        return 42;

    }



    /**

     * 鑾峰彇鏈嶅姟鍣ㄦ绘暟

     */

    public int getTotalServerCount() {

        return servers.size();

    }



    /**

     * 鑾峰彇鍚鍔ㄦ椂闂

     */

    public long getStartTime() {

        return startTime;

    }

}